﻿using BulletSharp;
using BulletSharp.Math;
using System;
using System.Collections.Generic;
using System.Text;

namespace ETModel {
    public static class BulletHelper {
        private static bool Inited = false;
        /// <summary>
        /// 初始化本插件,要在本库中任何一个组件之前调用(不能在事件里调用,推荐在程序入口处调用)
        /// </summary>
        public static void Init() {
            if (!Inited) {
                ETModel.Game.EventSystem.Add(typeof(BulletHelper).Assembly);
                Inited = true;
            }
        }

        /// <summary>
        /// 验证物理组件是否能被初始化,出错会直接throw,成功返回组件父级对象
        /// </summary>
        /// <param name="curr"></param>
        /// <returns></returns>
        public static Entity ComponentAwakeCheck(Component self) {
            if (BulletCollisionWorld.Instance == null) {
                throw new Exception("需要先初始化BulletCollisionWorld组件(建议给场景对象加这个组件)");
            }
            var entity = self.GetParent<Entity>();
            if (entity == null) {
                throw new Exception("附加的对象必须是Entity或子类");
            }
            return entity;
        }


        /// <summary>
        /// 使用顶点创建出物理形状
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="indices"></param>
        /// <param name="triangleCount">一般是indices/3</param>
        /// <returns></returns>
        public static CollisionShape CreateMeshShape(List<Vector3> vertices, List<int> indices,int triangleCount, Vector3 localScaling) {

            // Convert file data to TriangleMesh
            var trimesh = new TriangleMesh();
            int i;
            for (i = 0; i < triangleCount; i++) {
                int index0 = indices[i * 3];
                int index1 = indices[i * 3 + 1];
                int index2 = indices[i * 3 + 2];

                Vector3 vertex0 = vertices[index0] * localScaling;
                Vector3 vertex1 = vertices[index1] * localScaling;
                Vector3 vertex2 = vertices[index2] * localScaling;

                trimesh.AddTriangleRef(ref vertex0, ref vertex1, ref vertex2);
            }

            return new BvhTriangleMeshShape(trimesh, true);
        }
        /// <summary>
        /// 从.obj文件中创建出物理形状
        /// </summary>
        /// <param name="objFilePath"></param>
        /// <returns></returns>
        public static CollisionShape CreateMeshShapeFromObjFile(string objFilePath, Vector3 localScaling) {
            var wo = new WavefrontObj();
            int tcount = wo.LoadObj(objFilePath);
            if (tcount <= 0) return null;
            return CreateMeshShape(wo.Vertices, wo.Indices, tcount, localScaling);
        }


        public static Vector3 ToBullet(this UnityEngine.Vector3 vector3) {
            return new Vector3(vector3.x, vector3.y, vector3.z);
        }
        public static UnityEngine.Vector3 ToU3D(this Vector3 vector3) {
            return new UnityEngine.Vector3(vector3.X, vector3.Y, vector3.Z);
        }
        public static Quaternion ToBullet(this UnityEngine.Quaternion quaternion) {
            return new Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
        }
        public static UnityEngine.Quaternion ToU3D(this Quaternion quaternion) {
            return new UnityEngine.Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
        }
        public static Matrix ToBullet(this UnityEngine.Matrix4x4 matrix4x4) {
            var m = new Matrix();
            ToBullet(matrix4x4, ref m);
            return m;
        }
        public static void ToBullet(this UnityEngine.Matrix4x4 um, ref Matrix bm) {
            bm[0, 0] = um[0, 0];
            bm[1, 0] = um[0, 1];
            bm[2, 0] = um[0, 2];
            bm[3, 0] = um[0, 3];

            bm[0, 1] = um[1, 0];
            bm[1, 1] = um[1, 1];
            bm[2, 1] = um[1, 2];
            bm[3, 1] = um[1, 3];

            bm[0, 2] = um[2, 0];
            bm[1, 2] = um[2, 1];
            bm[2, 2] = um[2, 2];
            bm[3, 2] = um[2, 3];

            bm[0, 3] = um[3, 0];
            bm[1, 3] = um[3, 1];
            bm[2, 3] = um[3, 2];
            bm[3, 3] = um[3, 3];
        }

        public static UnityEngine.Matrix4x4 ToU3D(this Matrix bm) {
            UnityEngine.Matrix4x4 um = new UnityEngine.Matrix4x4();
            um[0, 0] = bm[0, 0];
            um[0, 1] = bm[1, 0];
            um[0, 2] = bm[2, 0];
            um[0, 3] = bm[3, 0];

            um[1, 0] = bm[0, 1];
            um[1, 1] = bm[1, 1];
            um[1, 2] = bm[2, 1];
            um[1, 3] = bm[3, 1];

            um[2, 0] = bm[0, 2];
            um[2, 1] = bm[1, 2];
            um[2, 2] = bm[2, 2];
            um[2, 3] = bm[3, 2];

            um[3, 0] = bm[0, 3];
            um[3, 1] = bm[1, 3];
            um[3, 2] = bm[2, 3];
            um[3, 3] = bm[3, 3];
            return um;
        }
        public static UnityEngine.Vector3 GetU3DVector3(this Matrix matrix) {
            return new UnityEngine.Vector3(matrix.M41, matrix.M42, matrix.M43);
        }
        public static UnityEngine.Quaternion GetU3DRotation(this Matrix matrix) {
            //return matrix.Orientation.ToU3D();

            UnityEngine.Vector3 forward;
            forward.x = matrix.M31;
            forward.y = matrix.M32;
            forward.z = matrix.M33;

            UnityEngine.Vector3 upwards;
            upwards.x = matrix.M21;
            upwards.y = matrix.M22;
            upwards.z = matrix.M23;

            return UnityEngine.Quaternion.LookRotation(forward, upwards);
        }

        public static void SetU3DVector3(this Matrix matrix, ref UnityEngine.Vector3 vector3) {
            matrix.M41 = vector3.x;
            matrix.M42 = vector3.y;
            matrix.M43 = vector3.z;
        }
    }
}
